package Model;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class MonteCarloSimulationMultiThread extends MonteCarloSimulation {
		
		public MonteCarloSimulationMultiThread(){
			super();
		}
		
		public double standartOption( String CallPutFlag, final double S, final double X, double T, double r, double b, double v, final int nSteps, int nSimulations){
				double dt;
				double Sum = 0, Drift, vSqrdt;
				int i, z = 0;
				final int numberOfCores = Runtime.getRuntime().availableProcessors();
			    final double blockingCoefficient = 0.1;
			    final int poolSize = (int)(numberOfCores / (1 - blockingCoefficient));

			    final List<Callable<Double>> partitions = new ArrayList<Callable<Double>>();
				
				dt = T / nSteps;
				
				Drift = (b - Math.pow(v,2) / 2) * dt;
				
				vSqrdt = v * Math.sqrt(dt);
				if (CallPutFlag=="call")
				  z=1;
				else if (CallPutFlag=="put")
				  z = -1;
				
				final int z2=z;
				final double Drift2=Drift;
				final double vSqrdt2=vSqrdt;
				  
				for(i = 1; i<=nSimulations; i++){
				   
				   partitions.add(new Callable<Double>() {
				        public Double call() throws Exception {
				           int j;
				           double St = S;
				           Random rand = new Random();
				           for(j = 1; j<=nSteps;j++){
						    	St = St * Math.exp(Drift2 + vSqrdt2 * rand.nextGaussian());
						   }
						   return Math.max(z2 * (St - X), 0);
				        }        
				   }); 
				}
				 final ExecutorService executorPool = Executors.newFixedThreadPool(poolSize);    
				 List<Future<Double>> list;
				 try {
					list = executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS);
					for(final Future<Double> S1 : list)
						try {
							Sum+=S1.get();
						} catch (InterruptedException | ExecutionException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} 

					 executorPool.shutdown();
					 return Math.exp(-r * T) * (Sum / nSimulations);
					 
				 } catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				 }
				 
		   return 0.0;
		}
		
		public void getData() {
			try {
				reader = new BufferedReader(new FileReader("data"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			String info = null;
			
			try {
				while((info = reader.readLine()) != null) {
					String[] infoData = info.split(",");
					Option option = new Option(null,Double.parseDouble(infoData[0]),Double.parseDouble(infoData[1]),Double.parseDouble(infoData[2]),Double.parseDouble(infoData[3]),Double.parseDouble(infoData[4]),Double.parseDouble(infoData[5]),Integer.parseInt(infoData[6]),Integer.parseInt(infoData[7]));
					options.add(option);
			    }
			} catch (NumberFormatException | IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		public ArrayList<Option> getOptions() {
			return options;
		}

		public void setOptions(ArrayList<Option> options) {
			this.options = options;
		}
}
